/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.etop.weibo.dao;

import com.etop.weibo.util.HibernateUtil;
import com.etop.weibo.util.WeiBoException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Query;
import org.hibernate.Session;

/**
 *
 * @author jansing lz_jansing@163.com
 */
public class BaseDao<T> implements IBaseDao<T> {

    private Class<T> persistentClass;
    private String tableName;
    private Field[] fields;

    public BaseDao() {
        persistentClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
        tableName = getDeadName(persistentClass.getName());
        fields = persistentClass.getDeclaredFields();
    }

    private String getDeadName(String className) {
        String name = className;
        if (name.indexOf(".") > 0) {
            name = name.substring(name.lastIndexOf(".") + 1);
        }
        return name;
    }

    /**
     * 生成参数字符串，因为参数是用户输入的，需要防止SQL注入攻击
     *
     * @param condition
     * @return
     */
    private String createCondition(Map<String, Object> condition) {
        StringBuilder conditionString = new StringBuilder();
        if (condition == null || condition.isEmpty()) {
            conditionString.append(" 1=1");
        } else {
            Set<Map.Entry<String, Object>> set = condition.entrySet();
            boolean flag = false;
            for (Map.Entry me : set) {
                if (flag) {
                    conditionString.append(" and");
                } else {
                    flag = true;
                }
                String keyName = me.getKey().toString();
                conditionString.append(" ").append(keyName).append("=:").append(keyName);
            }
        }
        return conditionString.toString();
    }

    /**
     * 生成select参数
     *
     * @param params
     * @return
     */
    private String createCondition(List<String> params) {
        StringBuilder conditionString = new StringBuilder();
        if (params == null || params.isEmpty()) {
            throw new WeiBoException("错误，没有参数！");
        } else {
            boolean flag = false;
            for (String param : params) {
                if (flag) {
                    conditionString.append(",");
                } else {
                    flag = true;
                }
                conditionString.append(param);
            }
        }
        return conditionString.toString();
    }

    /**
     * 生成update set参数，因为是程序生成的，无需检查SQL攻击。
     *
     * @param condition
     * @return
     */
    private String createInnerCondition(Map<String, Object> condition) {
        StringBuilder conditionString = new StringBuilder();
        if (condition == null || condition.isEmpty()) {
            throw new WeiBoException("参数错误，无参数！");
        } else {
            Set<Map.Entry<String, Object>> set = condition.entrySet();
            boolean flag = false;
            for (Map.Entry me : set) {
                if (flag) {
                    conditionString.append(",");
                } else {
                    flag = true;
                }
                String keyName = me.getKey().toString();
                String value = me.getValue().toString();
                conditionString.append(" ").append(keyName).append("=").append(value);
            }
        }
        return conditionString.toString();
    }

    private void setProperties(Query q, Map<String, Object> params) {
        if (params == null || params.isEmpty()) {
            throw new WeiBoException("错误！未设置参数");
        }
        Set<Map.Entry<String, Object>> set = params.entrySet();
        try {
            for (Map.Entry me : set) {
                String keyName = getDeadName(me.getKey().toString().trim());
                Object value = me.getValue();
                for (Field f : fields) {
                    if (f.getName().equals(keyName)) {
                        if (f.getType() == int.class) {
                            q.setInteger(keyName, Integer.valueOf(value.toString()));
                        } else if (f.getType() == String.class || f.getType() == Character.class) {
                            q.setString(keyName, value.toString());
                        } else if (f.getType() == Boolean.class) {
                            q.setBoolean(keyName, Boolean.valueOf(value.toString()));
                        } else if (f.getType() == Date.class) {
                            q.setTimestamp(keyName, Timestamp.valueOf(value.toString()));
                        } else if (f.getType() == Float.class) {
                            q.setFloat(keyName, Float.valueOf(value.toString()));
                        } else if (f.getType() == Double.class) {
                            q.setDouble(keyName, Double.valueOf(value.toString()));
                        } else if (f.getType() == Long.class) {
                            q.setLong(keyName, Long.valueOf(value.toString()));
                        } else if (f.getType() == Short.class) {
                            q.setShort(keyName, Short.valueOf(value.toString()));
                        } else {
                            //下面这些暂时没用
//                        q.setBigDecimal(keyName, BigDecimal.ONE);
//                        q.setBigInteger(keyName, BigInteger.ONE);
//                        q.setBinary(keyName, bytes);
//                        q.setByte(keyName, b);
//                        q.setCalendar(keyName, null);
//                        q.setCalendarDate(keyName, null);
//                        q.setCharacter(keyName, c);
//                        q.setSerializable(keyName, fields);
//                        q.setText(keyName, keyName);
                            throw new WeiBoException("无此属性名");
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new WeiBoException("BaseDao中参数错误！" + e.getMessage());
        }
    }

    @Override
    public void add(T obj) {
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            session.beginTransaction();
            session.save(obj);
            session.getTransaction().commit();
        } catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    @Override
    public void update(T obj) {
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            session.beginTransaction();
            session.update(obj);
            session.getTransaction().commit();
        } catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    @Override
    public void updateByHQL(Map<String, Object> params, Map<String, Object> condition) {
        StringBuilder hql = new StringBuilder();
        hql.append("update ").append(tableName).append(" set ")
                .append(createInnerCondition(params))
                .append(" where ")
                .append(createCondition(condition));
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            session.beginTransaction();
            session.createQuery(hql.toString()).executeUpdate();
            session.getTransaction().commit();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    @Override
    public void delete(int id) {
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            session.beginTransaction();
            T obj = (T) session.load(persistentClass, id);
            session.delete(obj);
            session.getTransaction().commit();
        } catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    @Override
    public void deleteByHQL(Map<String, Object> condition) {
        StringBuilder hql = new StringBuilder();
        hql.append("delete from ").append(tableName).append(" where");
        hql.append(createCondition(condition));
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            session.beginTransaction();
            Query query = session.createQuery(hql.toString());
            setProperties(query, condition);
            query.executeUpdate();
            session.getTransaction().commit();
        } catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }

    @Override
    public T load(int id) {
        Session session = HibernateUtil.openSession();
        T obj;
        try {
            obj = (T) session.get(persistentClass, id);
        } finally {
            session.close();
        }
        return obj;
    }

    @Override
    public T loadByHQL(Map<String, Object> condition) {
        StringBuilder hql = new StringBuilder();
        if (condition == null || condition.isEmpty()) {
            throw new WeiBoException("错误，没有参数!");
        }
        hql.append("from ").append(tableName).append(" where");
        hql.append(createCondition(condition));
        Session session = HibernateUtil.openSession();
        T obj;
        try {
            Query query = session.createQuery(hql.toString());
            setProperties(query, condition);
            obj = (T) query.uniqueResult();
        } finally {
            session.close();
        }
        return obj;
    }

    @Override
    public Object[] loadByHQL(List<String> params, Map<String, Object> condition) {
        StringBuilder hql = new StringBuilder();
        if (params == null || params.isEmpty() || condition == null || condition.isEmpty()) {
            throw new WeiBoException("错误，没有参数!");
        }
        hql.append("select ");
        hql.append(createCondition(params));
        hql.append(" from ").append(tableName).append(" where");
        hql.append(createCondition(condition));
        Session session = HibernateUtil.openSession();
        Object[] obj;
        try {
            Query query = session.createQuery(hql.toString());
            setProperties(query, condition);
            obj = (Object[]) query.uniqueResult();
        } finally {
            session.close();
        }
        return obj;
    }

    @Override
    public List<T> list() {
        StringBuilder hql = new StringBuilder();
        hql.append("from ").append(tableName);
        Session session = HibernateUtil.openSession();
        List<T> list;
        try {
            list = session.createQuery(hql.toString()).list();
        } finally {
            session.close();
        }
        return list;
    }

    @Override
    public List<T> listAndSort(String sort) {
        StringBuilder hql = new StringBuilder();
        if (sort.equals("asc") || sort.equals("desc")) {
            hql.append("from ").append(tableName).append(" ").append(sort);
            Session session = HibernateUtil.openSession();
            List<T> list;
            try {
                list = session.createQuery(hql.toString()).list();
            } finally {
                session.close();
            }
            return list;
        } else {
            throw new WeiBoException("参数错误，未知顺序!");
        }
    }

    @Override
    public List<T> listByHQL(Map<String, Object> condition) {
        StringBuilder hql = new StringBuilder();
        hql.append("from ").append(tableName).append(" where");
        hql.append(createCondition(condition));
        Session session = HibernateUtil.openSession();
        List<T> list;
        try {
            Query query = session.createQuery(hql.toString());
            setProperties(query, condition);
            list = query.list();
        } finally {
            session.close();
        }
        return list;
    }

    @Override
    public List<T> listByHQLAndSort(Map<String, Object> condition, String sort) {
        StringBuilder hql = new StringBuilder();
        hql.append("from ").append(tableName).append(" where");
        hql.append(createCondition(condition));
        hql.append(" ").append(sort);
        Session session = HibernateUtil.openSession();
        List<T> list;
        try {
            list = session.createQuery(hql.toString()).list();
        } finally {
            session.close();
        }
        return list;
    }
}
